package com.itheima.d4_synchronized_code;

public class Account {
    private String cardId; // 卡号
    private double money; // 余额。

    public Account() {
    }

    public Account(String cardId, double money) {
        this.cardId = cardId;
        this.money = money;
    }

    //对于静态方法建议使用字节码文件对象作为锁对象。也就是（类名.class）
    //分析：静态方法是被所有线程通过类名访问，那么要锁住所有线程，那么类名.class本身只有一份，锁住当前访问静态方法的所有线程，只允许一个线程进来
    public static void test(){
        synchronized (Account.class){

        }
    }

    // 小明 小红线程同时过来的
    public void drawMoney(double money) {   //这个money是调用这个方法时传过来的参数，而不是account类上面定义的money
        // 先搞清楚是谁来取钱？
        //当前哪个线程调用该方法，就取哪个线程对象的名字
        String name = Thread.currentThread().getName();
        // 1、判断余额是否足够
        // this正好代表共享资源！如果是小明小红两个线程过来，那么this就代表acc账户对象。如果是小黑小白两个线程，this代表acc1账户对象
        //建议使用共享资源作为锁对象，对于实例方法建议使用this作为锁对象。
        synchronized (this) {
            if(this.money >= money){    //当前账户对象的余额是否大于调用drawMoney想取的钱
                System.out.println(name + "来取钱" + money + "成功！");
                this.money -= money;
                System.out.println(name + "来取钱后，余额剩余：" + this.money);
            }else {
                System.out.println(name + "来取钱：余额不足~");
            }
        }

/*     把访问共享资源的核心代码给上锁，以此保证线程安全
       对于当前同时执行的线程来说，同步锁必须是同一把（同一个对象）
       磊哥：其实可以随便写一个字符串对象，因为双引号的字符串对象是在常量池里面的，计算机中只有一份
            并且对小明小红线程来说是同一个对象，所以可以锁住这两个线程

       假设现在在ThreadTest里面再创建一个账户对象2，然后再创建两个线程小黑小白去使用这个账户，
       但是现在“黑马”对象是唯一的，当小明使用账户1的时候，会加锁，所以小黑想要使用账户2也是无法使用的，这不合理
       所以这个锁对象锁的范围太大，对于所有线程来说都是同一个对象
       应该是使用账户1的线程有自己的锁对象，账户2的线程也有自己的锁对象
       所以官方建议，用共享资源作为锁
        synchronized ("黑马") {
            if(this.money >= money){
                System.out.println(name + "来取钱" + money + "成功！");
                this.money -= money;
                System.out.println(name + "来取钱后，余额剩余：" + this.money);
            }else {
                System.out.println(name + "来取钱：余额不足~");
            }
        }*/
    }

    public String getCardId() {
        return cardId;
    }

    public void setCardId(String cardId) {
        this.cardId = cardId;
    }

    public double getMoney() {
        return money;
    }

    public void setMoney(double money) {
        this.money = money;
    }


}
